package com.dbflow5.models;

import com.dbflow5.TestDatabase;
import com.dbflow5.annotation.*;
import com.dbflow5.converter.TypeConverters;
import com.dbflow5.database.FlowCursor;
import com.dbflow5.query.LoadFromCursorListener;

public class ForeignKeyModels {

    /**
     * Example of simple foreign key object with one foreign key object.
     */
    @Table(database = TestDatabase.class)
    public static class Blog{
        @PrimaryKey(autoincrement = true)
        public int id;
        @Column
        public String name;
        @ForeignKey(saveForeignKeyModel = true)
        public Author author;

        public int getId() {
            return id;
        }

        public void setId(int id) {
            this.id = id;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public Author getAuthor() {
            return author;
        }

        public void setAuthor(Author author) {
            this.author = author;
        }

        public Blog(int id, String name, Author author) {
            this.id = id;
            this.name = name;
            this.author = author;
        }
    }

    /**
     * Parent used as foreign key reference.
     */
    @Table(database = TestDatabase.class)
    public static class Author{
        @PrimaryKey(autoincrement = true)
        public int id;
        @Column
        public String firstName;
        @Column
        public String lastName;

        public int getId() {
            return id;
        }

        public void setId(int id) {
            this.id = id;
        }

        public String getFirstName() {
            return firstName;
        }

        public void setFirstName(String firstName) {
            this.firstName = firstName;
        }

        public String getLastName() {
            return lastName;
        }

        public void setLastName(String lastName) {
            this.lastName = lastName;
        }

        public Author(int id, String firstName, String lastName) {
            this.id = id;
            this.firstName = firstName;
            this.lastName = lastName;
        }
    }

    /**
     * Example of simple foreign key object with its [ForeignKey] deferred.
     */
    @Table(database = TestDatabase.class)
    public static class BlogDeferred{
        @PrimaryKey(autoincrement = true)
        public int id;
        @Column
        public String name;
        @ForeignKey(deferred = true)
        public Author author;

        public int getId() {
            return id;
        }

        public void setId(int id) {
            this.id = id;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public Author getAuthor() {
            return author;
        }

        public void setAuthor(Author author) {
            this.author = author;
        }

        public BlogDeferred(int id, String name, Author author) {
            this.id = id;
            this.name = name;
            this.author = author;
        }
    }

    /**
     * Class has example of single foreign key with [ForeignKeyReference] specified
     */
    @Table(database = TestDatabase.class)
    public static class BlogRef{
        @PrimaryKey
        public int id;
        @PrimaryKey
        public String name;
        @ForeignKey(references = {@ForeignKeyReference(columnName = "authorId", foreignKeyColumnName = "id", defaultValue = "not gonna work")})
        public Author author;

        public int getId() {
            return id;
        }

        public void setId(int id) {
            this.id = id;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public Author getAuthor() {
            return author;
        }

        public void setAuthor(Author author) {
            this.author = author;
        }

        public BlogRef(int id, String name, Author author) {
            this.id = id;
            this.name = name;
            this.author = author;
        }
    }

    /**
     * Class has example of single foreign key with [ForeignKeyReference] specified that is not the model object.
     */
    @Table(database = TestDatabase.class)
    public static class BlogRefNoModel{
        @PrimaryKey(autoincrement = true)
        public int id;
        @Column
        public String name;
        @ForeignKey(references = {@ForeignKeyReference(columnName = "authorId", foreignKeyColumnName = "id", notNull = @NotNull(onNullConflict = ConflictAction.FAIL))},
                tableClass = Author.class)
        public String authorId;

        public int getId() {
            return id;
        }

        public void setId(int id) {
            this.id = id;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public String getAuthorId() {
            return authorId;
        }

        public void setAuthorId(String authorId) {
            this.authorId = authorId;
        }

        public BlogRefNoModel(int id, String name, String authorId) {
            this.id = id;
            this.name = name;
            this.authorId = authorId;
        }
    }

    /**
     * Class has example of single foreign key with [ForeignKeyReference] as [PrimaryKey]
     */
    @Table(database = TestDatabase.class)
    public static class BlogPrimary{
        @PrimaryKey @ForeignKey
        public Author author;
        @Column
        public int id;

        public Author getAuthor() {
            return author;
        }

        public void setAuthor(Author author) {
            this.author = author;
        }

        public int getId() {
            return id;
        }

        public void setId(int id) {
            this.id = id;
        }

        public BlogPrimary(Author author, int id) {
            this.author = author;
            this.id = id;
        }
    }

    /**
     * Example of simple foreign key object with one foreign key object thats [ForeignKey.stubbedRelationship]
     *  and [ForeignKey.deleteForeignKeyModel] and [ForeignKey.saveForeignKeyModel]
     */
    @Table(database = TestDatabase.class)
    public static class BlogStubbed implements LoadFromCursorListener {
        @PrimaryKey(autoincrement = true)
        public int id;
        @Column
        public String name;
        @ForeignKey(stubbedRelationship = true, deleteForeignKeyModel = true, saveForeignKeyModel = true,
                onDelete = ForeignKeyAction.CASCADE, onUpdate = ForeignKeyAction.RESTRICT)
        public Author author;
        public String setter;
        public String getter;

        public int getId() {
            return id;
        }

        public void setId(int id) {
            this.id = id;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public Author getAuthor() {
            return author;
        }

        public void setAuthor(Author author) {
            this.author = author;
        }

        public String getSetter() {
            return setter;
        }

        public void setSetter(String setter) {
            this.setter = setter;
        }

        public String getGetter() {
            return getter;
        }

        public void setGetter(String getter) {
            this.getter = getter;
        }

        public BlogStubbed(int id, String name, Author author, String setter, String getter) {
            this.id = id;
            this.name = name;
            this.author = author;
            this.setter = setter;
            this.getter = getter;
        }

        @Override
        public void onLoadFromCursor(FlowCursor cursor) {
        }
    }

    public static class DoubleToDouble{
        public double _double;

        public DoubleToDouble(double _double) {
            this._double = _double;
        }
    }

    @TypeConverter
    public static class DoubleConverter extends TypeConverters.TypeConverter<Double, DoubleToDouble> {

        public DoubleConverter() {
            super();
        }

        @Override
        public Double getDBValue(DoubleToDouble model) {
            return model != null? model._double : null;
        }

        @Override
        public DoubleToDouble getModelValue(Double data) {
            if(data != null) {
                return new DoubleToDouble(data);
            }
            return null;
        }
    }

    public static class Location{
        public DoubleToDouble latitude;
        public DoubleToDouble longitude;

        public DoubleToDouble getLatitude() {
            return latitude;
        }

        public void setLatitude(DoubleToDouble latitude) {
            this.latitude = latitude;
        }

        public DoubleToDouble getLongitude() {
            return longitude;
        }

        public void setLongitude(DoubleToDouble longitude) {
            this.longitude = longitude;
        }

        public Location(DoubleToDouble latitude, DoubleToDouble longitude) {
            this.latitude = latitude;
            this.longitude = longitude;
        }
    }

    @Table(database = TestDatabase.class)
    public static class Position{
        @PrimaryKey
        public int id;
        @ColumnMap
        public Location location;

        public int getId() {
            return id;
        }

        public void setId(int id) {
            this.id = id;
        }

        public Location getLocation() {
            return location;
        }

        public void setLocation(Location location) {
            this.location = location;
        }

        public Position(int id, Location location) {
            this.id = id;
            this.location = location;
        }
    }

    @Table(database = TestDatabase.class)
    public static class Position2{
        @PrimaryKey
        public int id;
        @ColumnMap(references = {
                @ColumnMapReference(columnName = "latitude", columnMapFieldName = "latitude", defaultValue = "40.6"),
                @ColumnMapReference(columnName = "longitude", columnMapFieldName = "longitude", defaultValue = "55.5")})
        public Location location;

        public int getId() {
            return id;
        }

        public void setId(int id) {
            this.id = id;
        }

        public Location getLocation() {
            return location;
        }

        public void setLocation(Location location) {
            this.location = location;
        }

        public Position2(int id, Location location) {
            this.id = id;
            this.location = location;
        }
    }

    public static class Location2{
        public DoubleToDouble latitude;
        public Double longitude;

        public DoubleToDouble getLatitude() {
            return latitude;
        }

        public void setLatitude(DoubleToDouble latitude) {
            this.latitude = latitude;
        }

        public Double getLongitude() {
            return longitude;
        }

        public void setLongitude(Double longitude) {
            this.longitude = longitude;
        }

        public Location2(DoubleToDouble latitude, Double longitude) {
            this.latitude = latitude;
            this.longitude = longitude;
        }
    }

    @Table(database = TestDatabase.class)
    public static class PositionWithTypeConverter{
        @PrimaryKey
        public int id;
        @ColumnMap(references = {@ColumnMapReference(columnName = "latitude",
                columnMapFieldName = "latitude", typeConverter = DoubleConverter.class),
        @ColumnMapReference(columnName = "longitude", columnMapFieldName = "longitude")})
        public Location2 location;

        public int getId() {
            return id;
        }

        public void setId(int id) {
            this.id = id;
        }

        public Location2 getLocation() {
            return location;
        }

        public void setLocation(Location2 location) {
            this.location = location;
        }

        public PositionWithTypeConverter(int id, Location2 location) {
            this.id = id;
            this.location = location;
        }
    }

    @Table(database = TestDatabase.class)
    public static class NotNullReferenceModel{
        @PrimaryKey
        public String name;
        @NotNull @ForeignKey
        public SimpleTestModels.SimpleModel model;

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public SimpleTestModels.SimpleModel getModel() {
            return model;
        }

        public void setModel(SimpleTestModels.SimpleModel model) {
            this.model = model;
        }

        public NotNullReferenceModel(String name, SimpleTestModels.SimpleModel model) {
            this.name = name;
            this.model = model;
        }
    }
}


